/**
	Copyright (c) 2010 ATTi 
	All rights reserved.
	Author: Michael Shu
	Date: 3/17/2010
	Last Modified Date: 9/12/2011
*/

public without sharing class caseUpdateContactAccountClass {
	public static void limitAutoAssoiciationContactbyWebEmail(List<Case> natos, List<Case> iogs){
		for(Case c : natos){
			if(c.Origin == 'Email' && c.ContactId != null){
				c.ContactId = null;
				c.AccountId = null;
			}
		}
		List<Case> caseWithContactId = new List<Case>();
		Set<ID> conctIds = new Set<ID>();
		for(Case c : iogs){
			if(c.Origin == 'Email' && c.ContactId != null){
				conctIds.add(c.ContactId);
				caseWithContactId.add(c);
			}
		}
		if(!conctIds.isEmpty()){
			Map<ID, Contact> nonIOGcontacts = new Map<ID, Contact>([select id from Contact where ID IN: conctIds and RecordType.Name NOT IN: GeneralConstants.RT_IOG_CONTACT]);
			for(Case c : caseWithContactId){
				if(nonIOGcontacts.containsKey(c.ContactId)){
					c.ContactId = null;
					c.AccountId = null;
				}
			}
		}
	}
	
	public static void copyWebEmailToCaseContactEmailInitially(List<Case> natos){
		for(Case c : natos){
			if(c.Origin == 'Email' && c.SuppliedEmail != null && c.Case_Contact_Email__c == null && GeneralConstants.isValidEmailFormat(c.SuppliedEmail)){
				c.Case_Contact_Email__c = c.SuppliedEmail;
			}
		}		
	}
	
	public static void updateParentAccountOfContact(List<Case> cases){
		if(!cases.isEmpty()){
			Map<Id, Id> mContactIdbyAccId = new Map<Id, Id>();
			for(Case c : cases){		
				mContactIdbyAccId.put(c.ContactId, c.AccountId);
			}
			List<Contact> lAllContact = new List<Contact>([select Id, AccountId, CreatedDate, OwnerId from Contact where Id IN: mContactIdbyAccId.keySet()]);
			List<Contact> lUpdateContact = new List<Contact>();
			for(Contact ct_item : lAllContact){
				if(ct_item.AccountId == null && ct_item.CreatedDate.addMinutes(5) > datetime.now() && ct_item.OwnerId == UserInfo.getUserId()){
					ct_item.AccountId = mContactIdbyAccId.get(ct_item.Id);
					lUpdateContact.add(ct_item);
				}
			}
				
			if(!lUpdateContact.isEmpty()){
				try{
					update lUpdateContact;
				}catch(Exception ex){
					//GeneralConstants.mailAnyExceptionToMe('caseUpdateContactAccountClass', ' Update the parent account of the quickly created contacts fail ', ex);
					System.debug('Exception in update the Contact\'s Account associated with the case: ' + ex);
				}
			}
		}
	}
	
	public static void followAndunfollowCases(List<Case> followCases, List<Case> unfollowCases, Boolean isInsert){
		if(!unfollowCases.isEmpty()){
			Set<ID> unfollowCaseIds = new Set<ID>();
			for(Case c : unfollowCases){
				unfollowCaseIds.add(c.Id);
			}
			List<EntitySubscription> followersToRemove = [select ID from EntitySubscription where ParentId IN: unfollowCaseIds];
			try{
				delete followersToRemove;
			}catch(Exception ex){
				GeneralConstants.mailAnyExceptionToMe('caseUpdateContactAccountClass', 'Automatically un-follow case fail ', ex);
			}
		}
		if(!followCases.isEmpty()){
			List<EntitySubscription> followersToAdd = new List<EntitySubscription>();
			Set<ID> accountids = new Set<ID>();
			Set<ID> caseids = new Set<ID>();
			for(Case c : followCases){
				accountids.add(c.AccountId);
				caseids.add(c.Id);
			}
			List<EntitySubscription> accountfollowers = [select ParentId, SubscriberId, Subscriber.Profile.Name from EntitySubscription where ParentId IN: accountids];
			Set<ID> fAcctIds = new Set<ID>();
			Set<ID> fUserIds = new Set<ID>();
			for(EntitySubscription e : accountfollowers){
				fAcctIds.add(e.ParentId);
				fUserIds.add(e.SubscriberId);
			}
			Map<ID, Integer> countCasesOfAccount = new Map<ID, Integer>();
			Map<ID, Integer> countRecsAlreadyFollowed = new Map<ID, Integer>();
			if(!fAcctIds.isEmpty()){
				AggregateResult[] groupedResultsAcct = [select AccountId, Count(CaseNumber) cntcase from Case where isClosed = false and AccountId IN: fAcctIds group by AccountId];
				for (AggregateResult ar : groupedResultsAcct) {
					countCasesOfAccount.put((String)ar.get('AccountId'), (Integer)ar.get('cntcase'));
				}				
			}
			if(!fUserIds.isEmpty()){
				AggregateResult[] groupedResultsUser = [select SubscriberId, Count(ParentId) cntparent from EntitySubscription where SubscriberId IN: fUserIds group by SubscriberId];
				for (AggregateResult ar : groupedResultsUser) {
					countRecsAlreadyFollowed.put((String)ar.get('SubscriberId'), (Integer)ar.get('cntparent'));
				}
			}
			Map<ID, Set<ID>> acctmap = new Map<ID, Set<ID>>();
			for(EntitySubscription f : accountfollowers){
				Boolean isCotainerAccount = countCasesOfAccount.get(f.ParentId) != null && countCasesOfAccount.get(f.ParentId) >= 300;
				Boolean isOverFollowLimit = countRecsAlreadyFollowed.get(f.SubscriberId) != null && countRecsAlreadyFollowed.get(f.SubscriberId) >= 500;
				if(!isCotainerAccount && !isOverFollowLimit && !f.Subscriber.Profile.Name.startsWith('System Administrator')){
					Set<ID> fIds;
					if(acctmap.containsKey(f.ParentId)){
						fIds = acctmap.get(f.ParentId);
					}else{
						fIds = new Set<ID>();
					}
					fIds.add(f.SubscriberId);
					acctmap.put(f.ParentId, fIds);
				}
			}
			Map<ID, Set<ID>> casemap = new Map<ID, Set<ID>>();
			if(!isInsert){ // update
				List<EntitySubscription> casefollowers = [select ParentId, SubscriberId from EntitySubscription where ParentId IN: caseids];
				for(EntitySubscription f : casefollowers){
					Set<ID> fIds;
					if(casemap.containsKey(f.ParentId)){
						fIds = casemap.get(f.ParentId);
					}else{
						fIds = new Set<ID>();
					}
					fIds.add(f.SubscriberId);
					casemap.put(f.ParentId, fIds);
				}
			}
			if(isInsert){ // insert
				for(Case c : followCases){
					Set<ID> userIds = acctmap.get(c.AccountId);
					if(userIds != null){
						for(ID uId : userIds){
							EntitySubscription newfollower = new EntitySubscription();
							newfollower.ParentId = c.Id;
							newfollower.SubscriberId = uId;
							followersToAdd.add(newfollower);
						}	
					}				
				}
			}else{ // update
				for(Case c : followCases){
					Set<ID> userIds = acctmap.get(c.AccountId);
					Set<ID> casefollowerIds = casemap.get(c.Id);
					if(userIds != null){
						for(ID uId : userIds){
							if(casefollowerIds == null || (casefollowerIds != null && !casefollowerIds.contains(uId))){
								EntitySubscription newfollower = new EntitySubscription();
								newfollower.ParentId = c.Id;
								newfollower.SubscriberId = uId;
								followersToAdd.add(newfollower);
							}
						}	
					}				
				}
			}
			try{
				insert followersToAdd;
			}catch(Exception ex){
				GeneralConstants.mailAnyExceptionToMe('caseUpdateContactAccountClass', 'Automatically follow case fail ', ex);
			}
		}
	}
	
	
}